1   /*
2    * Copyright (C) 2011 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.primitives;
18  
19  import com.google.caliper.BeforeExperiment;
20  import com.google.caliper.Benchmark;
21  
22  import java.util.Random;
23  
24  /**
25   * Benchmarks for certain methods of {@code UnsignedLongs}.
26   *
27   * @author Eamonn McManus
28   */
29  public class UnsignedLongsBenchmark {
30    private static final int ARRAY_SIZE = 0x10000;
31    private static final int ARRAY_MASK = 0x0ffff;
32    private static final Random RANDOM_SOURCE = new Random(314159265358979L);
33    private static final long[] longs = new long[ARRAY_SIZE];
34    private static final long[] divisors = new long[ARRAY_SIZE];
35    private static final String[] decimalStrings = new String[ARRAY_SIZE];
36    private static final String[] binaryStrings = new String[ARRAY_SIZE];
37    private static final String[] hexStrings = new String[ARRAY_SIZE];
38    private static final String[] prefixedHexStrings = new String[ARRAY_SIZE];
39  
40    @BeforeExperiment
41    void setUp() {
42      for (int i = 0; i < ARRAY_SIZE; i++) {
43        longs[i] = random();
44        divisors[i] = randomDivisor(longs[i]);
45        decimalStrings[i] = UnsignedLongs.toString(longs[i]);
46        binaryStrings[i] = UnsignedLongs.toString(longs[i], 2);
47        hexStrings[i] = UnsignedLongs.toString(longs[i], 16);
48        prefixedHexStrings[i] = "0x" + hexStrings[i];
49      }
50    }
51  
52    @Benchmark long divide(int reps) {
53      long tmp = 0;
54      for (int i = 0; i < reps; i++) {
55        int j = i & ARRAY_MASK;
56        tmp += UnsignedLongs.divide(longs[j], divisors[j]);
57      }
58      return tmp;
59    }
60  
61    @Benchmark long remainder(int reps) {
62      long tmp = 0;
63      for (int i = 0; i < reps; i++) {
64        int j = i & ARRAY_MASK;
65        tmp += UnsignedLongs.remainder(longs[j], divisors[j]);
66      }
67      return tmp;
68    }
69  
70    @Benchmark long parseUnsignedLong(int reps) {
71      long tmp = 0;
72      // Given that we make three calls per pass, we scale reps down in order
73      // to do a comparable amount of work to other measurements.
74      int scaledReps = reps / 3 + 1;
75      for (int i = 0; i < scaledReps; i++) {
76        int j = i & ARRAY_MASK;
77        tmp += UnsignedLongs.parseUnsignedLong(decimalStrings[j]);
78        tmp += UnsignedLongs.parseUnsignedLong(hexStrings[j], 16);
79        tmp += UnsignedLongs.parseUnsignedLong(binaryStrings[j], 2);
80      }
81      return tmp;
82    }
83  
84    @Benchmark long parseDecode10(int reps) {
85      long tmp = 0;
86      for (int i = 0; i < reps; i++) {
87        int j = i & ARRAY_MASK;
88        tmp += UnsignedLongs.decode(decimalStrings[j]);
89      }
90      return tmp;
91    }
92  
93    @Benchmark long parseDecode16(int reps) {
94      long tmp = 0;
95      for (int i = 0; i < reps; i++) {
96        int j = i & ARRAY_MASK;
97        tmp += UnsignedLongs.decode(prefixedHexStrings[j]);
98      }
99      return tmp;
100   }
101 
102   @Benchmark int toString(int reps) {
103     int tmp = 0;
104     // Given that we make three calls per pass, we scale reps down in order
105     // to do a comparable amount of work to other measurements.
106     int scaledReps = reps / 3 + 1;
107     for (int i = 0; i < scaledReps; i++) {
108       int j = i & ARRAY_MASK;
109       long x = longs[j];
110       tmp += UnsignedLongs.toString(x).length();
111       tmp += UnsignedLongs.toString(x, 16).length();
112       tmp += UnsignedLongs.toString(x, 2).length();
113     }
114     return tmp;
115   }
116 
117   private static long random() {
118     return RANDOM_SOURCE.nextLong();
119   }
120 
121   // A random value that cannot be 0 and that is unsigned-less-than or equal
122   // to the given dividend, so that we don't have half of our divisions being
123   // trivial because the divisor is bigger than the dividend.
124   // Using remainder here does not give us a uniform distribution but it should
125   // not have a big impact on the measurement.
126   private static long randomDivisor(long dividend) {
127     long r = RANDOM_SOURCE.nextLong();
128     if (dividend == -1) {
129       return r;
130     } else {
131       return UnsignedLongs.remainder(r, dividend + 1);
132     }
133   }
134 }